/**
  ******************************************************************************
  * @file I2C/M24C08_EEPROM/i2c_ee.c 
  * @author  MCD Application Team
  * @version  V3.0.0
  * @date  04/06/2009
  * @brief  This file provides a set of functions needed to manage the
  *         communication between I2C peripheral and I2C M24C08 EEPROM.
  ******************************************************************************
  * @copy
  *
  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  *
  * <h2><center>&copy; COPYRIGHT 2009 STMicroelectronics</center></h2>
  */ 

/* Includes ------------------------------------------------------------------*/
#include "i2c_ee.h"
#include "stm32f10x_rcc.h"
#include "misc.h"
/** @addtogroup StdPeriph_Examples
  * @{
  */

/** @addtogroup I2C_M24C08_EEPROM
  * @{
  */ 

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/

/******* specified by user ************/
//#define I2C_REMAP
//#define SLAVE_10BIT_ADDRESS
/* timeout for check target's internal write procedure --> set 1s as max */
#define CHECK_TIMEOUT   (1000000*one_us_unit) 

#define BUS_BUSY_TIMEOUT (i2c_10clk_us*one_us_unit)*100
#define SEND_START_TIMEOUT  (i2c_10clk_us*one_us_unit)*100
#define SEND_ADDR7_TIMEOUT  (i2c_10clk_us*one_us_unit)*100
#define SEND_ADDR_HEADER_TIMEOUT  (i2c_10clk_us*one_us_unit)*100
#define SEND_DATA_TIMEOUT (i2c_10clk_us*one_us_unit)*100
#define RECEIVE_DATA_TIMEOUT (i2c_10clk_us*one_us_unit)*100

#define WAIT_COMM_TIMEOUT 
#define RECEIVE_STOP_TIMEOUT (i2c_10clk_us*one_us_unit)/5
/******* specify by user ************/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
uint16_t EEPROM_ADDRESS;

static uint32_t one_us_unit=0;
static uint32_t i2c_10clk_us=0;
static __IO bool I2C_OT = FALSE;

/* Private function prototypes -----------------------------------------------*/
void GPIO_Configuration(void);
void I2C_Configuration(void);

/* Private functions ---------------------------------------------------------*/

/**
  * @brief  Configure the used I/O ports pin
  * @param  None
  * @retval : None
  */
void systick_isr()
{
  I2C_OT = TRUE;
  *(uint32_t *)0xe000e010 &= 0xfffffffe;     //SysTick_CounterCmd(SysTick_Counter_Disable);
}

/*    SCL   SDA     remaped SCL   SDA
I2C1  PB.6  PB.7      PB.8        PB.9
I2C2  PB.10 PB.11

PB.ODR : ((u32 *)0x40010c0c) 

<PB.0~7> @ 0x40010c0c
PB.6(I2C1.SCL) set *((u8 *)0x40010c0c) |=0x40;  reset *((u8* )0x40010c0c) &= 0xbf; 
PB.7(I2C1SDA) set *((u8 *)0x40010c0c) |=0x80;  reset *((u8* )0x40010c0c) &= 0x7f; 

<PB.9~15> @ 0x40010c0d
PB.8(remap I2C1.SCL) set *((u8 *)0x40010c0d) |=0x01;  reset *((u8* )0x40010c0c) &= 0xfe;  
PB.9(remap I2C1.SDA) set *((u8 *)0x40010c0d) |=0x02;  reset *((u8* )0x40010c0c) &= 0xfd; 

PB.10(I2C2.SCL) set *((u8 *)0x40010c0d) |=0x04;  reset *((u8* )0x40010c0c) &= 0xfb;  
PB.11(I2C2.SDA) set *((u8 *)0x40010c0d) |=0x08;  reset *((u8* )0x40010c0c) &= 0xf7; 
*/


/**
  * @brief  configu check the status of the line of I2C, and recove it.
  * @param  None
  * @retval : None
  */
void SysTick_configuration(void)
{

}

/**
  * @brief  check the status of the line of I2C, and recover it.
  * @param  None
  * @retval : None
  */
void I2C_Comm_Verify(I2C_TypeDef* I2Cx)
{
  GPIO_InitTypeDef  GPIO_InitStructure; 
  __IO uint32_t i=0,j=0;
  __IO uint16_t tmp=0;
  
  if (I2Cx == I2C1)   /* enable I2C clock */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
  else
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
  
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); /* enable GPIOB clock */
  
  if (I2Cx == I2C1)
  {
    #ifdef I2C_REMAP
    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_8 | GPIO_Pin_9;
    #else
    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7;
    #endif
  }
  else {
    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_10 | GPIO_Pin_11;
  }
  
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOB, &GPIO_InitStructure);        /* initiate the SCK&SDA to input */
  
  tmp = GPIOB->IDR;   /* get the status of the SCK&SDA */
  
  if (I2Cx == I2C1)
  {
#ifdef I2C_REMAP
    if (!(tmp & GPIO_Pin_8) && (tmp & GPIO_Pin_9)) /* if the SCK&SDK is not High */
    {
      GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_8 | GPIO_Pin_9;  /* send 9 clocks to recover it */
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
      GPIO_Init(GPIOB, &GPIO_InitStructure);
          
      j = 9;
      while(j--)
      {
        GPIOB->BSRR = 0x00000100;   /* SCK High */
        i=0xf;
        while(i--);       /* delay */
        GPIOB->BSRR = 0x01000000;   /* SCK Low */
        i=0xf;
        while(i--);       /* delay */
      }
      GPIOB->BSRR = 0x00000300;   /* SCK & DATA High */
    } 
    #else
    if (!(tmp & GPIO_Pin_6) && (tmp & GPIO_Pin_7)) /* if the SCK&SDK is not High */
    {
      GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7;  /* send 9 clocks to recover it */
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
      GPIO_Init(GPIOB, &GPIO_InitStructure);
      
      j = 9;
      while(j--)
      {
        GPIOB->BSRR = 0x00000040;  /* SCK High */
        i=0xf;
        while(i--);       /* delay */
        GPIOB->BSRR = 0x00400000; /* SCK Low */
        i=0xf;
        while(i--);     /* delay */
      }
      GPIOB->BSRR = 0x000000c0; /* SCK & DATA High */
    }  
    #endif
  }
  else
  {
    if (!(tmp & GPIO_Pin_10) && (tmp & GPIO_Pin_11)) /* if the SCK&SDK is not High */
    {
      /* send 9 clock out using GPIO emulation */
      GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_10 | GPIO_Pin_11;  /* send 9 clocks to recover it */
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
      GPIO_Init(GPIOB, &GPIO_InitStructure);
          
      j = 9;
      while(j--)
      {
        GPIOB->BSRR = 0x00000400;   /* SCK High */
        i=0xf;
        while(i--);    /* delay */
        GPIOB->BSRR = 0x04000000; /* SCK Low */
        i=0xf;
        while(i--);   /* delay */
      }
      GPIOB->BSRR = 0x00000c00; /* SCK & DATA High */
    } 
  }
}


void  I2C_Comm_Init(I2C_TypeDef* I2Cx, uint32_t I2CSpeed, uint16_t I2CAddr)
{
  GPIO_InitTypeDef  GPIO_InitStructure; 
  RCC_ClocksTypeDef  rcc_clocks;
  I2C_InitTypeDef  I2C_InitStructure;
  uint32_t hclk;
     
  if(I2Cx == I2C1)
  {
#ifdef I2C_REMAP
    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_8 | GPIO_Pin_9;
#else
    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7;
#endif
  }
  else if (I2Cx == I2C2)
  {
    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_10| GPIO_Pin_11;
  }
    
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
  
/*********** I2C periphral configuration **********/
  I2C_DeInit(I2Cx);
  I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; /* fixed */
  I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;  /* fixed */
  I2C_InitStructure.I2C_OwnAddress1 = I2CAddr;  /* user parameter */
  I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; /* fixed */
  I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
  I2C_InitStructure.I2C_ClockSpeed = I2CSpeed; /* user parameter */
  I2C_Cmd(I2Cx, ENABLE);
  I2C_Init(I2Cx, &I2C_InitStructure);
  
/********** SysTick for timeout configuration *****/
  RCC_GetClocksFreq(&rcc_clocks);
  hclk = rcc_clocks.HCLK_Frequency;
  SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);
  one_us_unit = hclk/1000000;
  i2c_10clk_us = 1000000*10/I2CSpeed;
  *(uint32_t *)0xe000e010 |= 2;                   //SysTick_ITConfig(ENABLE);
}

I2C_Result  I2C_Comm_MasterSend(I2C_TypeDef* I2Cx, uint16_t slaveaddr, uint8_t offset, uint8_t* pBuffer, uint32_t length)
{
__IO uint32_t check_time = 0;

    /*wait 5us min for bus free time limitation for later transaction*/
    *(uint32_t *)0xe000e014 = one_us_unit*5;     //SysTick_SetReload(one_us_unit*5);
    *(uint32_t *)0xe000e018 = 0;                 //SysTick_CounterCmd(SysTick_Counter_Clear);
    *(uint32_t *)0xe000e010 |= 1;                //SysTick_CounterCmd(SysTick_Counter_Enable);
    while(!I2C_OT);
    *(uint32_t *)0xe000e010 &= 0xfffffffe;       //SysTick_CounterCmd(SysTick_Counter_Disable);
    I2C_OT = FALSE;    
    
    
    /*wait bus free*/
    *(uint32_t *)0xe000e014 = BUS_BUSY_TIMEOUT;  //SysTick_SetReload(BUS_BUSY_TIMEOUT);
    *(uint32_t *)0xe000e018 = 0;                 //SysTick_CounterCmd(SysTick_Counter_Clear);
    *(uint32_t *)0xe000e010 |= 1;                //SysTick_CounterCmd(SysTick_Counter_Enable);
    while((I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY))&&(!I2C_OT));
    *(uint32_t *)0xe000e010 &= 0xfffffffe;       //SysTick_CounterCmd(SysTick_Counter_Disable);
    if (I2C_OT)
    {
      I2C_OT = FALSE;
      return BUS_BUSY;
    } 
    
    
    /*send start and wait*/
    I2C_GenerateSTART(I2Cx, ENABLE);
    *(uint32_t *)0xe000e014 = SEND_START_TIMEOUT;  //SysTick_SetReload(SEND_START_TIMEOUT);
    *(uint32_t *)0xe000e018 = 0;                   //SysTick_CounterCmd(SysTick_Counter_Clear);
    *(uint32_t *)0xe000e010 |= 1;                  //SysTick_CounterCmd(SysTick_Counter_Enable);
    while(!(I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT) || I2C_OT)); 
    *(uint32_t *)0xe000e010 &= 0xfffffffe;         //SysTick_CounterCmd(SysTick_Counter_Disable);
    if (I2C_OT)
    {
      I2C_OT = FALSE;
      return SEND_START_ERR;
    }  
    
    
    /* send 7-bit slave address and wait */
    I2C_Send7bitAddress(I2Cx, (u8)(slaveaddr & 0xFF), I2C_Direction_Transmitter);
    *(uint32_t *)0xe000e014 = SEND_ADDR7_TIMEOUT;  //SysTick_SetReload(SEND_ADDR7_TIMEOUT);
    *(uint32_t *)0xe000e018 = 0;                   //SysTick_CounterCmd(SysTick_Counter_Clear);
    *(uint32_t *)0xe000e010 |= 1;                  //SysTick_CounterCmd(SysTick_Counter_Enable);
    while(!(I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) || I2C_OT));  
    *(uint32_t *)0xe000e010 &= 0xfffffffe;         //SysTick_CounterCmd(SysTick_Counter_Disable);
    if (I2C_OT)
    {
      I2C_OT = FALSE;
      I2C_GenerateSTOP(I2Cx, ENABLE);
      while ((I2Cx->CR1 & 0x200) == 0x200);   //wait while stop bit not cleared 
      if(I2C_GetFlagStatus(I2Cx, I2C_FLAG_AF))
        I2C_ClearFlag(I2Cx, I2C_FLAG_AF);
      return ADDR_MATCH_ERR;
    }   
        
    /* send offset if needed */
    if (offset != 0xff)
    {
      I2C_SendData(I2Cx, offset); 
      *(uint32_t *)0xe000e014 = SEND_DATA_TIMEOUT; //SysTick_SetReload(SEND_DATA_TIMEOUT);
      *(uint32_t *)0xe000e018 = 0;                 //SysTick_CounterCmd(SysTick_Counter_Clear);
      *(uint32_t *)0xe000e010 |= 1;                //SysTick_CounterCmd(SysTick_Counter_Enable);
      while(!(I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED) || I2C_OT));
      *(uint32_t *)0xe000e010 &= 0xfffffffe;       //SysTick_CounterCmd(SysTick_Counter_Disable);
      if (I2C_OT)
      {
        I2C_OT = FALSE;
        I2C_GenerateSTOP(I2Cx, ENABLE);
        while ((I2Cx->CR1 & 0x200) == 0x200);   //wait while stop bit not cleared 
        if(I2C_GetFlagStatus(I2Cx, I2C_FLAG_AF)) 
          I2C_ClearFlag(I2Cx, I2C_FLAG_AF);
        return DATA_TIMEOUT;
      } 
    }
  

    I2C_SendData(I2Cx, *pBuffer++);
    length--;
    while (length--)
    {
        *(uint32_t *)0xe000e014 = SEND_DATA_TIMEOUT; 
        *(u32 *)0xe000e018 = 0;                 
        *(uint32_t *)0xe000e010 |= 1;               
        while (((I2C_GetLastEvent(I2Cx) & 0x04) != 0x04)&&(!I2C_OT));  
        *(uint32_t *)0xe000e010 &= 0xfffffffe;  
        if (I2C_OT)
        {
          I2C_OT = FALSE;
          I2C_GenerateSTOP(I2Cx, ENABLE);
          while ((I2Cx->CR1 & 0x200) == 0x200); 
          if(I2C_GetFlagStatus(I2Cx, I2C_FLAG_AF)) 
            I2C_ClearFlag(I2Cx, I2C_FLAG_AF);
          return DATA_TIMEOUT;
        }
        I2C_SendData(I2Cx, *pBuffer++);
    }
    *(uint32_t *)0xe000e014 = SEND_DATA_TIMEOUT; 
    *(uint32_t *)0xe000e018 = 0;                 
    *(uint32_t *)0xe000e010 |= 1; 
    while (!(I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED) || I2C_OT));
    *(uint32_t *)0xe000e010 &= 0xfffffffe; 
    if (I2C_OT)
    {
      I2C_OT = FALSE;
      I2C_GenerateSTOP(I2Cx, ENABLE);
      while ((I2Cx->CR1 & 0x200) == 0x200); 
      if(I2C_GetFlagStatus(I2Cx, I2C_FLAG_AF)) 
        I2C_ClearFlag(I2Cx, I2C_FLAG_AF);
      return DATA_TIMEOUT;
    }


    /* send stop to close communication */
    I2C_GenerateSTOP(I2Cx, ENABLE);
  
   
   
    /* launch check write status procedure */
    while(check_time != 1000000/5)
    {
      /*wait 5us min for bus free time limitation for later transaction : check phase*/
      *(uint32_t *)0xe000e014 = one_us_unit*5;     //SysTick_SetReload(one_us_unit*5);
      *(uint32_t *)0xe000e018 = 0;                 //SysTick_CounterCmd(SysTick_Counter_Clear);
      *(uint32_t *)0xe000e010 |= 1;                //SysTick_CounterCmd(SysTick_Counter_Enable);
      while(!I2C_OT);
      *(uint32_t *)0xe000e010 &= 0xfffffffe;       //SysTick_CounterCmd(SysTick_Counter_Disable);
      I2C_OT = FALSE;  
    
      /* wait bus for free */
      *(uint32_t *)0xe000e014 = CHECK_TIMEOUT;
      *(uint32_t *)0xe000e018 = 0;
      *(uint32_t *)0xe000e010 |= 1;
      while((I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY))&&(!I2C_OT));
      *(uint32_t *)0xe000e010 &= 0xfffffffe; 
      I2C_OT = FALSE;
      if (I2C_OT)
      {
        I2C_OT = FALSE;
        /* during 1s, bus is occupied by other i2c comm */  
        /* after check_timeout(1s), target's internal must complete */
        return NO_ERR;
      }      
      

      I2C_GenerateSTART(I2Cx, ENABLE);
      while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT)); 
      I2C_Send7bitAddress(I2Cx, slaveaddr, I2C_Direction_Transmitter);
      
       /* wait for 10 I2C clock pulse period and then check ADDR set or not*/
      *(uint32_t *)0xe000e014 = one_us_unit*i2c_10clk_us;
      *(uint32_t *)0xe000e018 = 0;
      *(uint32_t *)0xe000e010 |= 1;
      while(!I2C_OT);
      *(uint32_t *)0xe000e010 &= 0xfffffffe; 
      I2C_OT = FALSE;

      if(I2C_GetFlagStatus(I2Cx, I2C_FLAG_ADDR))
      {
        break;
      }
      I2C_ClearFlag(I2Cx, I2C_FLAG_AF);   
      I2C_GenerateSTOP(I2Cx, ENABLE); 
      while ((I2Cx->CR1 & 0x200) == 0x200);    
    
      check_time++;
    }

    if (check_time ==1000000/5)
      return WRITE_FAILURE;

    I2C_ClearFlag(I2Cx, I2C_FLAG_AF);   
    I2C_GenerateSTOP(I2Cx, ENABLE); 
    while ((I2Cx->CR1 & 0x200) == 0x200);    
    
    return NO_ERR;
}

I2C_Result  I2C_Comm_MasterReceive(I2C_TypeDef* I2Cx, uint16_t slaveaddr, uint8_t offset, uint8_t* pBuffer, uint32_t length)
{   
  /* wait 5us max for bus free time limitation for later transaction */
  *(uint32_t *)0xe000e014 = one_us_unit*5;
  *(uint32_t *)0xe000e018 = 0;
  *(uint32_t *)0xe000e010 |= 1;
  while(!I2C_OT);
  *(uint32_t *)0xe000e010 &= 0xfffffffe; 
  I2C_OT = FALSE;  

  /* wait bus free */
  *(uint32_t *)0xe000e014 = BUS_BUSY_TIMEOUT;
  *(uint32_t *)0xe000e018 = 0;
  *(uint32_t *)0xe000e010 |= 1;
  while((I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY))&&(!I2C_OT));
  *(uint32_t *)0xe000e010 &= 0xfffffffe; 
  if (I2C_OT)
  {
    I2C_OT = FALSE;
    return BUS_BUSY;
  }
  
  /* send start and wait */
  I2C_GenerateSTART(I2Cx, ENABLE);
  *(uint32_t *)0xe000e014 = SEND_START_TIMEOUT;
  *(uint32_t *)0xe000e018 = 0;
  *(uint32_t *)0xe000e010 |= 1;
  while(!(I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT) || I2C_OT)); 
  *(uint32_t *)0xe000e010 &= 0xfffffffe; 
  if (I2C_OT)
  {
    I2C_OT = FALSE;
    return SEND_START_ERR;
  }
        
  /*
  if offset needed:
  (1) slave address with write direction
  (2) offset
  (3) re-start
  */
  if (offset!=0xff)
  {
    /* (1) */
    I2C_Send7bitAddress(I2Cx, (uint8_t)(slaveaddr & 0xFF), I2C_Direction_Transmitter);
    *(uint32_t *)0xe000e014 = SEND_ADDR7_TIMEOUT;
    *(uint32_t *)0xe000e018 = 0;
    *(uint32_t *)0xe000e010 |= 1;
    while(!(I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) || I2C_OT));  
    *(u32 *)0xe000e010 &= 0xfffffffe; 
    if (I2C_OT)
    {
      I2C_OT = FALSE;
      I2C_GenerateSTOP(I2Cx, ENABLE);
      while ((I2Cx->CR1 & 0x200) == 0x200);    
      if(I2C_GetFlagStatus(I2Cx, I2C_FLAG_AF))
        I2C_ClearFlag(I2Cx, I2C_FLAG_AF); 
      return ADDR_MATCH_ERR;
    }
      
    
    /* (2) */
    I2C_SendData(I2Cx, offset); 
    *(uint32_t *)0xe000e014 = SEND_DATA_TIMEOUT;
    *(uint32_t *)0xe000e018 = 0;
    *(uint32_t *)0xe000e010 |= 1;
    while(!(I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED) || I2C_OT));
    *(uint32_t *)0xe000e010 &= 0xfffffffe; 
    if (I2C_OT)
    {
      I2C_OT = FALSE;
      I2C_GenerateSTOP(I2Cx, ENABLE);
      while ((I2Cx->CR1 & 0x200) == 0x200);    
      if(I2C_GetFlagStatus(I2Cx, I2C_FLAG_AF))
        I2C_ClearFlag(I2Cx, I2C_FLAG_AF); 
      return DATA_TIMEOUT;
    }
      
    
    /* (3) */
    I2C_GenerateSTART(I2Cx, ENABLE);
    *(uint32_t *)0xe000e014 = SEND_START_TIMEOUT;
    *(uint32_t *)0xe000e018 = 0;
    *(uint32_t *)0xe000e010 |= 1;
    while(!(I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT) || I2C_OT)); 
    *(uint32_t *)0xe000e010 &= 0xfffffffe; 
    if (I2C_OT)
    {
      I2C_OT = FALSE;
      return SEND_START_ERR;
    }   
  } 

  
  /* send addr with read direction */
  I2C_Send7bitAddress(I2Cx, (uint8_t)(slaveaddr & 0xFF), I2C_Direction_Receiver);
  
  
  /*
  different implementation of receive data 
  depends on communication length
  (1) length >=3
  (2) length = 2
  (3) length = 1
  */
  if (length >=3)
  {
    *(uint32_t *)0xe000e014 = SEND_ADDR7_TIMEOUT;  
    *(uint32_t *)0xe000e018 = 0;
    *(uint32_t *)0xe000e010 |= 1;
    while(!(I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) || I2C_OT));  
    *(uint32_t *)0xe000e010 &= 0xfffffffe;    
    if (I2C_OT)
    {
      I2C_OT = FALSE;
      I2C_GenerateSTOP(I2Cx, ENABLE);
      while ((I2Cx->CR1 & 0x200) == 0x200);    
      if(I2C_GetFlagStatus(I2Cx, I2C_FLAG_AF))
          I2C_ClearFlag(I2Cx, I2C_FLAG_AF); 
      return ADDR_MATCH_ERR;
    }    
    
    /* receive data */
    /* use another safe procedure to receive data */
    while(length)
    {
      if (length !=3)
      {
        *(uint32_t *)0xe000e014 = RECEIVE_DATA_TIMEOUT;   
        *(uint32_t *)0xe000e018 = 0;
        *(uint32_t *)0xe000e010 |= 1;
        while(((I2C_GetLastEvent(I2Cx)&0x04) != 0x04)&& !I2C_OT); // poll on BTF
        *(uint32_t *)0xe000e010 &= 0xfffffffe;     
        if (I2C_OT)
        {
          I2C_OT = FALSE;
          I2C_GenerateSTOP(I2Cx, ENABLE);
          return DATA_TIMEOUT;
        }    
        *pBuffer++ = I2C_ReceiveData(I2Cx);
        length--;
      }
      
      if (length == 3)
      {
        /* D(n-2) in DR; D(n-1) in shift register */
        *(uint32_t *)0xe000e014 = RECEIVE_DATA_TIMEOUT;   
        *(uint32_t *)0xe000e018 = 0;
        *(uint32_t *)0xe000e010 |= 1;
        while(((I2C_GetLastEvent(I2Cx)&0x04) != 0x04)&& !I2C_OT); // poll on BTF
        *(uint32_t *)0xe000e010 &= 0xfffffffe;     
        if (I2C_OT)
        {
          I2C_OT = FALSE;
          I2C_GenerateSTOP(I2Cx, ENABLE);
          return DATA_TIMEOUT;
        }        
        /* clear ACK */
        I2C_AcknowledgeConfig(I2Cx, DISABLE);     
        __disable_irq();       //NVIC_SETPRIMASK();
        /* read D(n-2) */
        *pBuffer++ = I2C_ReceiveData(I2Cx);      
        /* program stop */
        I2C_GenerateSTOP(I2Cx, ENABLE);    
        /* read D(n-1) */
        *pBuffer++ = I2C_ReceiveData(I2Cx);
        __enable_irq();      //NVIC_RESETPRIMASK();
        
        *(uint32_t *)0xe000e014 = RECEIVE_DATA_TIMEOUT;   
        *(uint32_t *)0xe000e018 = 0;
        *(uint32_t *)0xe000e010 |= 1;
        while(((I2C_GetLastEvent(I2Cx)&0x40) != 0x40)&& !I2C_OT); // poll on RxNE
        *(uint32_t *)0xe000e010 &= 0xfffffffe;     
        if (I2C_OT)
        {
          I2C_OT = FALSE;
          I2C_GenerateSTOP(I2Cx, ENABLE);
          return DATA_TIMEOUT;
        }
        *pBuffer = I2Cx->DR;
        length = 0;
      }
    }


    *(uint32_t *)0xe000e014 = RECEIVE_DATA_TIMEOUT;   
    *(uint32_t *)0xe000e018 = 0;
    *(uint32_t *)0xe000e010 |= 1;    
    while (((I2Cx->CR1 & 0x200) == 0x200)&&(!I2C_OT)); 
    *(uint32_t *)0xe000e010 &= 0xfffffffe;     
    if (I2C_OT)
    {
      I2C_OT = FALSE;
      return SEND_STOP_ERR;
    }
    
    
    
    I2C_AcknowledgeConfig(I2Cx, ENABLE);
  }
  else if (length == 2)
  {
    vu32 tmp;
    /* ACK=1,POS=1 */
    I2Cx->CR1 = 0xc01; 
    
    *(uint32_t *)0xe000e014 = SEND_ADDR7_TIMEOUT;   
    *(uint32_t *)0xe000e018 = 0;
    *(uint32_t *)0xe000e010 |= 1;
    while((!I2C_GetFlagStatus(I2Cx,I2C_FLAG_ADDR))&& !I2C_OT); //wait for ADDR event
    *(uint32_t *)0xe000e010 &= 0xfffffffe;     
    if (I2C_OT)
      {
        I2C_OT = FALSE;
        I2C_GenerateSTOP(I2Cx, ENABLE);
        return ADDR_MATCH_ERR;
      } 
    __disable_irq();  //NVIC_SETPRIMASK();
    /* clear ADDR */
    tmp = I2Cx->SR2;    
    /* disable ACK */
    I2C_AcknowledgeConfig(I2Cx, DISABLE);

    __enable_irq();   //NVIC_RESETPRIMASK();     
    
    *(uint32_t *)0xe000e014 = RECEIVE_DATA_TIMEOUT;   
    *(uint32_t *)0xe000e018 = 0;
    *(uint32_t *)0xe000e010 |= 1;
    while(((I2C_GetLastEvent(I2Cx)&0x0004) != 0x0004)&& !I2C_OT); // poll on BTF
    *(uint32_t *)0xe000e010 &= 0xfffffffe;     
    if (I2C_OT)
      {
        I2C_OT = FALSE;
        I2C_GenerateSTOP(I2Cx, ENABLE);
        return DATA_TIMEOUT;
      } 
    __disable_irq();  //NVIC_SETPRIMASK();   
    I2C_GenerateSTOP(I2Cx, ENABLE); 
    *pBuffer++ = I2Cx->DR;
    *pBuffer = I2Cx->DR;
    __enable_irq();   //NVIC_RESETPRIMASK();
    length = 0;
    /* POS=0; ACK=PE=1 */
    I2Cx->CR1 = 0x0401; 
  }
  else if (length == 1)
  {
    __IO uint32_t tmp;
    
    *(uint32_t *)0xe000e014 = SEND_ADDR7_TIMEOUT;   
    *(uint32_t *)0xe000e018 = 0;
    *(uint32_t *)0xe000e010 |= 1;
    while((!I2C_GetFlagStatus(I2Cx,I2C_FLAG_ADDR))&& !I2C_OT); //wait for ADDR event
    *(uint32_t *)0xe000e010 &= 0xfffffffe;     
    if (I2C_OT)
      {
        I2C_OT = FALSE;
        I2C_GenerateSTOP(I2Cx, ENABLE);
        return ADDR_MATCH_ERR;
      }   
    /* disable ACK */
    I2C_AcknowledgeConfig(I2Cx, DISABLE);

    __disable_irq();  //NVIC_SETPRIMASK();   
    /* clear ADDR */
    tmp = I2Cx->SR2;   
    I2C_GenerateSTOP(I2Cx, ENABLE);
    __enable_irq();   //NVIC_RESETPRIMASK();
    
    
    
    *(uint32_t *)0xe000e014 = RECEIVE_DATA_TIMEOUT;   
    *(uint32_t *)0xe000e018 = 0;
    *(uint32_t *)0xe000e010 |= 1;
    while(((I2C_GetLastEvent(I2Cx)&0x40) != 0x40)&& !I2C_OT); // poll on RxNE
    *(uint32_t *)0xe000e010 &= 0xfffffffe;     
    if (I2C_OT)
      {
        I2C_OT = FALSE;
        I2C_GenerateSTOP(I2Cx, ENABLE);
        return DATA_TIMEOUT;
      } 
    
    *pBuffer = I2Cx->DR;
    length = 0;
    while ((I2Cx->CR1 & 0x200) == 0x200); 
    I2C_AcknowledgeConfig(I2Cx, ENABLE);
  }
      
  return NO_ERR;
}


/**
  * @}
  */ 

/**
  * @}
  */ 

/******************* (C) COPYRIGHT 2009 STMicroelectronics *****END OF FILE****/
